package top.xia17.plugins.fast.quartz.core;

import cn.hutool.core.util.StrUtil;
import top.xia17.plugins.fast.common.spring.SpringContextHolder;
import top.xia17.plugins.fast.common.utils.TimeIntervalUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;

/**
 * 执行SpringBean的指定方法的Quartz任务
 *
 * @author xia17
 * @date 2022/6/13
 */
@Slf4j
public class BeanExecutionJob extends QuartzJobBean {


    @Override
    protected void executeInternal(JobExecutionContext context) {
        // 获取需要执行的任务信息
        QuartzJobInfo job = (QuartzJobInfo) context.getMergedJobDataMap().get(QuartzJobInfo.JOB_KEY);
        // 生成日志信息
        QuartzLogInfo quartzLogInfo = new QuartzLogInfo();
        quartzLogInfo.setQuartzJob(job);
        TimeIntervalUtil timeIntervalUtil = TimeIntervalUtil.createAndStart();
        try {
            // 获取bean
            Object bean = SpringContextHolder.getBean(job.getBeanName());
            // 获取方法
            Method method;
            if (StrUtil.isBlank(job.getParam())) {
                method = bean.getClass().getDeclaredMethod(job.getMethodName());
            } else {
                method = bean.getClass().getDeclaredMethod(job.getMethodName(), String.class);
            }
            // 执行方法
            method.setAccessible(true);
            if (StrUtil.isBlank(job.getParam())) {
                method.invoke(bean);
            } else {
                method.invoke(bean, job.getParam());
            }
        } catch (Exception e) {
            String msg = StrUtil.format("执行定时任务[beanName={},method={},param={}]时发生错误！", job.getBeanName(), job.getMethodName(), job.getParam());
            log.error(msg, e);
            quartzLogInfo.setIsSuccess(false);
            quartzLogInfo.setExceptionDetail(getStackTrace(e));
        } finally {
            long time = timeIntervalUtil.end();
            quartzLogInfo.setTime(time);
        }

    }


    private static String getStackTrace(Throwable throwable) {
        StringWriter sw = new StringWriter();
        try (PrintWriter pw = new PrintWriter(sw)) {
            throwable.printStackTrace(pw);
            return sw.toString();
        }
    }


}
